﻿Imports Algorithms
Public Class NPC

    'Each person needs thes basic things:
    'Home(Kitchen, DiningRoom, BedRooms)    The home inclueds the proprity and house.
    'Bedroom    Just a link to his bedroom in the house.

    Private WalkSpeed As Single = 60
    Private CookingTime As Single = 5
    Private EatingTime As Single = 0.48

    Public Home As Home.Home
    Public BedRoom As Home.BedRoom


    Private Texture As Integer

    Public Position As PointF
    Public GridPosition As Point
    Private LastGridPosiition As Point
    Private OldMap As Byte
    Private Angle As Single = 0


    Public Sub New(ByVal GridPosition As Point, ByVal Home As Home.Home, ByVal BedRoom As Home.BedRoom, ByVal Texture As Integer)
        Me.Home = Home
        Me.BedRoom = BedRoom
        Me.Texture = Texture
        Me.Position = New PointF((GridPosition.X * 16), (GridPosition.Y * 16))
        Me.GridPosition = GridPosition
        LastGridPosiition = GridPosition
        OldMap = Map(GridPosition.X, GridPosition.Y)
    End Sub

    Dim paths() As PathFinderNode
    Public Sub Render()
        'Draw the NPC.
        Scr2D.Draw_TextureRotated(Texture, Position.X + 8, Position.Y + 8, 16, 16, Angle)


        'If there is a path then draw it.
        If paths IsNot Nothing Then
            For Each path As PathFinderNode In paths
                Dim x As Integer = path.X * 16
                Dim y As Integer = path.Y * 16
                Scr2D.Draw_Box(x, y, x + 16, y + 16, GrgbA(0.5, 1))
            Next
        End If

        'Draw the grid postion of the npc.
        Dim gx As Single = GridPosition.X * 16
        Dim gy As Single = GridPosition.Y * 16
        Scr2D.Draw_Box(gx, gy, gx + 16, gy + 16, RGBA(1, 0, 0, 1))
    End Sub



    Private Hunger As Single = 72
    Private HungerSpeed As Single = 0.1
    Private Tired As Single = 143
    Private TiredSpeed As Single = 0.1



    Private Moving As Boolean = False 'Are we trying to get someware?
    Private Destination As Point 'Ware are we going?
    Private Eating, Cooking, Working, Sleeping As Byte 'Are we eating or working?  0=no 1=yes 2=trying to
    Private tmr As Single


    Public Sub Tick()
        'Update the grid position.
        GridPosition.X = System.Math.Round((Position.X) * 0.0625)
        GridPosition.Y = System.Math.Round((Position.Y) * 0.0625)
        'This checks to see if the grid position has moved. If it has, then it resets the old map and sets the new position to 0. So the npcs don't try to walk over each other. 
        If Not GridPosition.Equals(LastGridPosiition) Then
            Map(LastGridPosiition.X, LastGridPosiition.Y) = OldMap
            LastGridPosiition = GridPosition
            OldMap = Map(GridPosition.X, GridPosition.Y)
            Map(GridPosition.X, GridPosition.Y) = 0
        End If


        '###################################Eating
        If Eating = 1 Then 'I am eating.
            If Hunger > 0 Then 'Am i still hungey?
                tmr += World.Time.TimeElasped 'It takes time to eat...
                If tmr > EatingTime Then 'Can i fit more in?
                    Hunger -= 1 'Now i can get full..
                    tmr = 0
                End If
            Else
                'Stop eating
                Eating = 0
            End If

            'Need to get to the table.
        ElseIf Eating = 2 Then
            If MoveTo(Home.DiningRoom.GridPosition) Then
                Eating = 1
                Hunger = System.Math.Round(Hunger)
            End If

            '###################################Cooking
        ElseIf Cooking = 1 Then 'I am cooking.

            tmr += World.Time.TimeElasped 'It takes time to cook.
            If tmr > CookingTime Then 'Am i done cooking?
                Cooking = 0
                Eating = 2
                tmr = 0
            End If


            'Need to get to the kitchen.
        ElseIf Cooking = 2 Then
            If MoveTo(Home.Kitchen.GridPosition) Then Cooking = 1



            '###################################Sleeping
        ElseIf Sleeping = 1 Then 'I am tired.
            If Tired > 0 Then 'Am i still tired?
                tmr += World.Time.TimeElasped 'It takes time to sleep...
                If tmr > 3.13 Then
                    Tired -= 1
                    tmr = 0
                End If
            Else
                'Stop sleeping
                Sleeping = 0
            End If

            'Need to get to the bed.
        ElseIf Sleeping = 2 Then
            If MoveTo(BedRoom.GridPosition) Then
                Sleeping = 1
                Tired = System.Math.Round(Tired)
            End If



        Else
            'Scnece the npc is not doing anything make it think.
            Think()
        End If

        If Eating = 0 Then Hunger += HungerSpeed * World.Time.TimeElasped
        If Sleeping = 0 Then Tired += TiredSpeed * World.Time.TimeElasped

        DebugTxt = "Eating=" & Eating & vbNewLine & "Cooking=" & Cooking & vbNewLine & "Hunger=" & System.Math.Round(Hunger) & vbNewLine & "Tired=" & System.Math.Round(Tired)

    End Sub


    Private Sub Think()
        'What should the NPC do?

        'Do I want to eat?
        If Hunger > 72 Then
            Cooking = 2


        ElseIf Tired > 144 Then
            Sleeping = 2
        End If

    End Sub

    Private Function MoveTo(ByVal GridPosition As Point) As Boolean
        Map(LastGridPosiition.X, LastGridPosiition.Y) = OldMap

        'Find the path.
        Dim pf As New PathFinderFast(Map)
        pf.Formula = HeuristicFormula.MaxDXDY
        pf.Diagonals = False
        pf.HeavyDiagonals = False
        pf.HeuristicEstimate = 2
        pf.SearchLimit = 2000
        Dim path As List(Of PathFinderNode) = pf.FindPath(GridPosition, Me.GridPosition)
        Map(LastGridPosiition.X, LastGridPosiition.Y) = 0

        'The speed of the npc.
        Dim Speed As Single = WalkSpeed * World.Time.TimeElasped

        Dim npcX, npcY As Single

        Dim Move As New Point
        If path IsNot Nothing Then

            If path.Count > 1 Then
                Dim x As Integer = (path(1).X * 16)
                Dim y As Integer = (path(1).Y * 16)



                npcX = System.Math.Round(Position.X)
                npcY = System.Math.Round(Position.Y)

                If npcX > x Then
                    If Not SnapY(Speed) Then
                        Position.X -= Speed
                        Move.X = +1
                    End If
                ElseIf npcX < x Then
                    If Not SnapY(Speed) Then
                        Position.X += Speed
                        Move.X = -1
                    End If

                ElseIf npcY > y Then
                    If Not SnapX(Speed) Then
                        Position.Y -= Speed
                        Move.Y = +1
                    End If

                ElseIf npcY < y Then
                    If Not SnapX(Speed) Then
                        Position.Y += Speed
                        Move.Y = -1
                    End If

                End If

            End If

            'Set the angle of the npc.
            '0 45 90 135 180 225 270 315
            If ((Move.X = 0) And (Move.Y = 1)) Then
                Angle = 0 'Down
            ElseIf ((Move.X = 0) And (Move.Y = -1)) Then
                Angle = 180 'Up
            ElseIf ((Move.X = 1) And (Move.Y = 0)) Then
                Angle = 270 'Left
            ElseIf ((Move.X = -1) And (Move.Y = 0)) Then
                Angle = 90 'Right
            ElseIf ((Move.X = 1) And (Move.Y = -1)) Then
                Angle = 45 '0.8!
            ElseIf ((Move.X = -1) And (Move.Y = -1)) Then
                Angle = 315 '-0.8!
            ElseIf ((Move.X = 1) And (Move.Y = 1)) Then
                Angle = 135 '2.2!
            ElseIf ((Move.X = -1) And (Move.Y = 1)) Then
                Angle = 225 '-2.2!
            End If


            Me.paths = path.ToArray
            If path.Count = 1 Then
                If Not SnapX(Speed) And Not SnapY(Speed) Then
                    Return True
                Else
                    Return False
                End If
            Else
                Return False
            End If


        Else 'Could not find a path.
            Return False
        End If

    End Function

    Private Function SnapY(ByVal Speed As Single) As Boolean
        Dim y As Single = System.Math.Round(Position.Y / 16) * 16
        Dim cy As Single = System.Math.Round(Position.Y / 2) * 2
        If cy = y Then
            Position.Y = y
            Return False
        End If


        If cy < y Then
            Position.Y += Speed
        Else
            Position.Y -= Speed
        End If
        Return True
    End Function
    Private Function SnapX(ByVal Speed As Single) As Boolean
        Dim x As Single = System.Math.Round(Position.X / 16) * 16
        Dim cx As Single = System.Math.Round(Position.X / 2) * 2
        If cx = x Then
            Position.X = x
            Return False
        End If

        If cx < x Then
            Position.X += Speed
        Else
            Position.X -= Speed
        End If
        Return True
    End Function
End Class
